#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/algorithm/minmax_element.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/join.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>
#include <array>
#include <map>
#include <unordered_map>
#include <string>
#include <functional>
#include <iostream>
#include <algorithm>
#include <numeric>

using namespace boost;
using namespace boost::adaptors;
using namespace std;

namespace cosmos {
    //将lambda转为function
    template<typename Fun> //&应该是一个地址
    struct function_traits : public function_traits<decltype(&Fun::operator())> {
    };

    template<typename ClassType, typename ReturnType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const> {
        typedef std::function<ReturnType(Args...)> func;
    };

    template<typename Func>
    typename function_traits<Func>::func
    to_function(Func &&f) {
        return static_cast<typename function_traits<Func>::func>(f);
    }

    template<typename R>
    class LinqCpp {
        typedef typename R::value_type value_type;
    public:
        LinqCpp(R range) : m_linqrange(range) {
            //cout << "exec" << endl;
        }

        //过滤操作
        template<typename F>
        auto
        where(F &&f) -> LinqCpp<filtered_range<F, R>> {
            return LinqCpp<filtered_range<F, R>>(filter(m_linqrange, f));
        };

        //转换操作 运行出错
        template<typename F>
        auto
        select(const F &&f) ->
        LinqCpp<transformed_range<typename function_traits<F>::func, R>> {
            auto fn = to_function(f);
            return LinqCpp<transformed_range<typename function_traits<F>::func, R>>(
                    boost::adaptors::transform(m_linqrange, fn)
            );
        }

        auto begin() const -> decltype((boost::declval<const R>()).begin()) {
            return m_linqrange.begin();
        }

        auto end() const -> decltype((boost::declval<const R>()).end()) {
            return m_linqrange.end();
        }

        template<typename F>
        auto first(const F &&f) -> decltype(std::find_if(begin(), end(), f)) {
            return std::find_if(begin(), end(), f);
        }

        //反转
        auto reverse() -> LinqCpp<boost::reversed_range<R>> {
            return LinqCpp<boost::reversed_range<R>>(boost::adaptors::reverse(m_linqrange));
        };

        template<typename F>
        //auto
        void
        last(F &&f) //得看引用折叠
        //-> decltype(reverse().first(f))
        {
            auto lq = reverse();
            auto iter = lq.first(std::forward<F>(f));
            cout << *iter << endl;
        }

        bool empty() const {
            return begin() == end();
        }

        template<typename F>
        auto
        any(const F &&f) const -> bool {
            return std::any_of(begin(), end(), f);
        }

        template<typename F>
        auto
        all(const F &&f) const -> bool {
            return std::all_of(begin(), end(), f);
        }

        //根据判断式判断是否包含
        template<typename F>
        auto contains(const F &&f) const -> bool {
            return std::find_if(begin(), end(), f);
        }

        //根据function去重
        //template<typename F>
        //auto distinct(const F &&f) const -> LinqCpp<decltype(boost::unique(m_linqrange, f))> {
        //    return LinqCpp<R>(boost::unique(m_linqrange, f));
        //}

        //简单去重 结果不对
        //LinqCpp<boost::range_detail::uniqued_range<R>>
        auto distinct() -> LinqCpp<boost::range_detail::uniqued_range<R>> {
            return LinqCpp<boost::range_detail::uniqued_range<R>>(
                    m_linqrange | uniqued);
        }

        //累加器 对每一个元素进行运算
        template<typename F>
        auto aggregate(const F &&f) const -> value_type {
            auto it = begin();
            auto value = *it++;
            return std::accumulate(it, end(), std::move(value), f);
        }

        //算术运算
        auto sum() const -> value_type {
            return aggregate(std::plus<value_type>());
        }

        auto count() const -> decltype(std::distance(begin(), end())) {
            return std::distance(begin(), end());
        }

        template<typename F>
        auto count(const F &&f) const -> decltype(std::count_if(begin(), end(), f)) {
            return std::count_if(begin(), end(), f);
        }

        template<typename F>
        auto Min(const F &&f) const -> value_type {
            return *std::min_element(begin(), end(), f);
        }

        auto Min() const -> value_type {
            return *std::min_element(begin(), end());
        }

        template<typename F>
        auto Max(const F &&f) const -> value_type {
            return *std::max_element(begin(), end(), f);
        }

        auto Max() const -> value_type {
            return *std::max_element(begin(), end());
        }

        template<typename F>
        //返回一对pair
        auto minmax(const F &&f) const -> decltype(boost::minmax_element(begin(), end(), f)) {
            return boost::minmax_element(begin(), end(), f);
        }

        auto minmax() const -> decltype(boost::minmax_element(begin(), end())) {
            return boost::minmax_element(begin(), end());
        }

        //获取指定位置的索引
        template<typename T>
        auto elementat(T index) const -> decltype(std::next(begin(), index)) {
            return std::next(begin(), index);
        }

        //将map中的键放到一个range中 就是参数类型range传入map 把key重新组合起来组成新的range
        auto keys() const -> LinqCpp<boost::select_first_range<R>> {
            return LinqCpp<boost::select_first_range<R>>(boost::adaptors::keys(m_linqrange));
        }

        //将map中的值放到一个range中 就是参数类型range传入map 把value重新组合起来组成新的range
        auto values() const -> LinqCpp<boost::select_first_range<R>> {
            return LinqCpp<boost::select_first_range<R>>(boost::adaptors::values(m_linqrange));
        }

        //获取前面的n个元素 编译不过
        //template<typename T>
        //auto take(T n) const -> LinqCpp<decltype(slice(m_linqrange, 0, n))> {
        //    return LinqCpp<decltype(slice(m_linqrange, 0, n))>(slice(m_linqrange, 0, n));
        //}

        //将range转为vector
        vector<value_type> to_vector() {
            return vector<value_type>(begin(), end());
        }

        //当条件不满足时返回前面所有的元素
        template<typename F>
        auto
        takewhile1(const F &&f) const
        //->LinqCpp<boost::iterator_range<decltype(begin())>>  //用iterator_range就编译不过
        -> LinqCpp<decltype(boost::iterator_range<decltype(begin())>(begin(), std::find_if(begin(), end(), f)))> {
            return LinqCpp(boost::iterator_range<decltype(begin())>(begin(), std::find_if(begin(), end(), f)));;
        }

        template<typename F>
        auto
        takewhile(const F &&f) const
        //->LinqCpp<boost::iterator_range<decltype(begin())>>  //用iterator_range就编译不过 好像又能用了
        -> LinqCpp<decltype(boost::make_iterator_range(begin(), std::find_if(begin(), end(), f)))> {
            return LinqCpp(boost::make_iterator_range(begin(), std::find_if(begin(), end(), f)));;
        }

        //获取第n个元素之后的所有元素
        template<typename T>
        auto skip(T n) const -> LinqCpp<decltype(boost::make_iterator_range(begin() + n, end()))> {
            return LinqCpp(boost::make_iterator_range(begin() + n, end()));
        }

        //当条件不满足时，获取后面所有的元素
        template<typename F>
        auto skipwhile(const F &&f) const -> LinqCpp<decltype(boost::make_iterator_range(begin(),
                                                                                         std::find_if_not(begin(),
                                                                                                          end(), f)))> {
            return LinqCpp(boost::make_iterator_range(begin(), std::find_if_not(begin(), end(), f)));
        }

        //按步长挑选元素组成新集合
        //template<typename T>
        //auto step(T n) -> decltype(stride(m_linqrange, n)) { //error: 'm_linqrange' was not declared in this scope
        //    return stride(m_linqrange, n);
        //}

        //直接将指针或者智能指针指向的内容组成新集合
        auto indirect() -> LinqCpp<boost::indirect_iterator<R>> { //error: no type named 'value_type' in 'struct
            return LinqCpp<boost::indirected_range<R>>(boost::adaptors::indirect(m_linqrange)); //这个地方为什么要显示指定，上面不用显示指定
        }

        //连接操作
        template<typename R2>
        auto concat(const R2 &other) -> LinqCpp<joined_range<R, const R2>> {
            return LinqCpp<joined_range<R, const R2>>(boost::join(m_linqrange, other));
        }

        //排除操作
        //因为set_difference要求两个区间必须是有序的（从小到大排列），std::set和std::multiset为有序序列
        //set_difference可构造区间S1,S2的差集（出现于S1但不出现于S2的元素），即S1-S2;返回值为指向输出区间的尾端。
        template<typename R2>
        void except(const R2 &other, std::vector<value_type> &resultVector) {
            std::set_difference(begin(), end(), other.begin(), other.end(), back_inserter(resultVector));
        }

        //包含操作
        template<typename R2>
        bool includes(const R2 &other) const {
            return std::includes(begin(), end(), other.begin(), other.end());
        }

        //分组操作
        template<typename Fn>
        unordered_multimap<typename std::result_of<Fn(value_type)>::type, value_type>
        groupby(const Fn &&f) {
            typedef decltype(std::declval<Fn>()(std::declval<value_type>())) keytype;
            unordered_multimap<keytype, value_type> mymap;
            std::for_each(begin(), end(), [&mymap, &f](value_type item) {
                mymap.insert(make_pair(f(item), item));
            });
            return mymap;
        }

        //允许指定键和值函数的分组操作
        template<typename KeyFn, typename ValueFn>
        unordered_multimap<typename std::result_of<KeyFn(value_type)>::type,
                typename std::result_of<ValueFn(value_type)>::type>
        groupby(const KeyFn &&fnk, const ValueFn &&fnv) {
            typedef typename std::result_of<KeyFn(value_type)>::type keytype;
            typedef typename std::result_of<ValueFn(value_type)>::type valtype;
            unordered_multimap<keytype, valtype> mymap;
            std::for_each(begin(), end(), [&mymap, &fnk, &fnv](value_type item) {
                mymap.insert(make_pair(fnk(item), fnv(item)));
            });
            return mymap;
        }

        //转换操作  error: 'operator()' is not a member of 'const std::function
        template<typename T>
        auto cast(T t) -> LinqCpp<boost::transformed_range<std::function<T(value_type)>, R>> {
            std::function<T(value_type)> f = [](value_type item) {
                return static_cast<T>(item);
            };
            return LinqCpp<boost::transformed_range<std::function<T(value_type)>, R>>(select(std::move(f)));
        }

        //判断操作
        template<typename R2>
        bool equals(const LinqCpp<R2> &other) const {
            return count() == other.count() && std::equal(begin(), end(), other.begin());
        }

        template<typename R2, typename F>
        bool equals(const LinqCpp<R2> &other, const F &f) const {
            return count() == other.count() && std::equal(begin(), end(), other.begin(), f);
        }

        template<typename R2>
        bool operator==(const LinqCpp<R2> &other) const {
            return equals(other);
        }

        template<typename R2>
        bool operator!=(const LinqCpp<R2> &other) const {
            return !(*this == other);
        }

        //遍历操作
        template<typename F>
        void for_each(const F &&f) const {
            std::for_each(begin(), end(), f);
        }

    private:
        R m_linqrange;

    };
    //简化range的声明

    template<template<typename T> class IteratorRange, typename R>
    using Range = IteratorRange<decltype((declval<R>()).begin())>;

    template<typename R>
    using iter_range = Range<boost::iterator_range, R>;

    template<typename R>
    //LinqCpp<boost::iterator_range<decltype(std::declval<R>().begin())>>
    auto
    from(const R &range) ->
    LinqCpp<boost::iterator_range<decltype(range.begin())>> {
        //return LinqCpp<iter_range<R>>(iter_range<R>(range));
        //typedef decltype(std::declval<R>().begin()) it;
        //cout << typeid(it).name() << endl;
        //auto rg = boost::iterator_range<decltype(range.begin())>(range);
        //for(auto item : rg) {
        //    cout << item << " ";
        //}
        return LinqCpp<boost::iterator_range<decltype(range.begin())>>(
                boost::iterator_range<decltype(range.begin())>(range)
        );
    }

    //合并range
    template<typename ...T>
    auto
    zip(const T &... containers) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(
            std::begin(containers)...))>> {
        auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(containers)...));
        auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(containers)...));
        return boost::make_iterator_range(zip_begin, zip_end);
    }
}